﻿namespace Jsl.FxCop
{
    using System.Collections.Generic;
    using System.Windows.Forms;
    using Microsoft.VisualStudio.CodeAnalysis.Extensibility;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class When_evaluating_local_variables
    {
        [TestMethod]
        public void Local_is_assigned_a_more_specific_type()
        {
            var method = new CompileHelper()
                .AddMethod(@"
public object Method()
{
    object x = ""Xyz"";
    return x;
 }")
                .Generate(true)
                .GetMethod("Class", "Method");

            new UseStrongestType()
                .RunMethodRule(method)
                .HasProblem(
                    100,
                    FixCategories.NonBreaking,
                    MessageLevel.Warning,
                    "The variable 'x' of type 'Object' should be changed to type 'System.String'.")
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void Interface_wins_over_class()
        {
            var method = new CompileHelper()
                .AddAssemblyReference(typeof(IList<string>))
                .AddMethod(@"
public object Method()
{
    object x = new System.Collections.Generic.List<string>();
    x = (System.Collections.Generic.IList<string>)x;

    return x;
}")
                .Generate(true)
                .GetMethod("Class", "Method");

            new UseStrongestType()
                .RunMethodRule(method)
                .HasProblem(
                    100,
                    FixCategories.NonBreaking,
                    MessageLevel.Warning,
                    "The variable 'x' of type 'Object' should be changed to the following interface 'System.Collections.Generic.IList`1<System.String>'.")
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void Local_is_used_in_out_parameter()
        {
            var method = new CompileHelper()
                .AddAssemblyReference(typeof(Control))
                .AddSource(@"
using System.Windows.Forms;

public class Class
{
    public void Method(bool booleanValue)
    {
        Control control;
        if (booleanValue)
        {
            control = new Form();
        }
        else
        {
            this.MethodWithOutParameter(out control);
        }
    }

    private void MethodWithOutParameter(out Control parameter)
    {
        parameter = null;
    }
}")
                .Generate(true)
                .GetMethod("Class", "Method");

            // Control in the out parameter should win over Form in the assignment.
            new UseStrongestType()
                .RunMethodRule(method)
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void Setting_to_null_is_ignored()
        {
            var method = new CompileHelper()
                .AddMethod(@"
public string Method()
{
    string x = ""Xyz"";
    x = null;

    return x;
}")
                .Generate(true)
                .GetMethod("Class", "Method");

            new UseStrongestType()
                .RunMethodRule(method)
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void Never_set_other_than_null_is_ignored()
        {
            var method = new CompileHelper()
                .AddMethod(@"
public string Method()
{
    string x = null;
    x = null;

    return x;
}")
                .Generate(true)
                .GetMethod("Class", "Method");

            new UseStrongestType()
                .RunMethodRule(method)
                .HasNoMoreProblems();
        }

        [TestMethod]
        public void Initially_set_to_null_is_ignored()
        {
            var method = new CompileHelper()
                .AddMethod(@"
public System.CodeDom.Compiler.CodeDomProvider Method(bool booleanValue)
{
    System.CodeDom.Compiler.CodeDomProvider x = null;
    if (booleanValue)
    {
        x = new Microsoft.VisualBasic.VBCodeProvider();
    }
    else
    {
        x = new Microsoft.CSharp.CSharpCodeProvider();
    }

    return x;
}")
                .Generate(true)
                .GetMethod("Class", "Method");

            new UseStrongestType()
                .RunMethodRule(method)
                .HasNoMoreProblems();
        }
    }
}